package bb.lanxing.utils;

import android.animation.ArgbEvaluator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.text.TextUtils;

import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.Overlay;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.map.PolylineDottedLineType;
import com.baidu.mapapi.map.PolylineOptions;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.map.track.TraceOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.DistanceUtil;

import java.util.ArrayList;
import java.util.List;

import bb.lanxing.App;
import bb.lanxing.R;
import bb.lanxing.model.CurrentLocation;

public class MapUtil {
    /**
     * 最后一次定位信息
     */
    public static final String LAST_LOCATION = "last_location";

    private static MapUtil INSTANCE = new MapUtil();

    private MapStatus mapStatus = null;

    private Marker mMoveMarker = null;

    public TextureMapView mapView = null;

    public BaiduMap baiduMap = null;

    public LatLng lastPoint = null;

    private Context mContext;

    /**
     * 路线覆盖物
     */
    public Overlay polylineOverlay = null;

    private MapUtil() {
    }

    public static MapUtil getInstance() {
        return INSTANCE;
    }

    public void init(TextureMapView view) {
        mapView = view;
        baiduMap = mapView.getMap();
        mapView.showZoomControls(false);
        mContext = mapView.getContext();
    }

    public void onPause() {
        if (null != mapView) {
            mapView.onPause();
        }
    }

    public void onResume() {
        if (null != mapView) {
            mapView.onResume();
        }
    }

    public void clear() {
        lastPoint = null;
        if (null != mMoveMarker) {
            mMoveMarker.remove();
            mMoveMarker = null;
        }
        if (null != polylineOverlay) {
            polylineOverlay.remove();
            polylineOverlay = null;
        }
        if (null != baiduMap) {
            baiduMap.clear();
            baiduMap = null;
        }
        mapStatus = null;
        if (null != mapView) {
            mapView.onDestroy();
            mapView = null;
        }
    }

    /**
     * 设置地图中心：使用已有定位信息；
     *
     * @param trackApp
     */
    public void setCenter(App trackApp) {
        if (!CommonUtil.isZeroPoint(CurrentLocation.latitude, CurrentLocation.longitude)) {
            LatLng currentLatLng = new LatLng(CurrentLocation.latitude, CurrentLocation.longitude);
            updateStatus(currentLatLng, false);
            return;
        }
        String lastLocation = trackApp.trackConf.getString(LAST_LOCATION, null);
        if (!TextUtils.isEmpty(lastLocation)) {
            String[] locationInfo = lastLocation.split(";");
            if (!CommonUtil.isZeroPoint(Double.parseDouble(locationInfo[1]),
                    Double.parseDouble(locationInfo[2]))) {
                LatLng currentLatLng = new LatLng(Double.parseDouble(locationInfo[1]),
                        Double.parseDouble(locationInfo[2]));
                updateStatus(currentLatLng, false);
            }
        }
    }

    public void updateStatus(LatLng currentPoint, boolean showMarker) {
        if (null == baiduMap || null == currentPoint) {
            return;
        }

        if (null != baiduMap.getProjection()) {
            Point screenPoint = baiduMap.getProjection().toScreenLocation(currentPoint);
            // 点在屏幕上的坐标超过限制范围，则重新聚焦底图
            if (screenPoint.y < 200 || screenPoint.y > App.screenHeight - 500
                    || screenPoint.x < 200 || screenPoint.x > App.screenWidth - 200
                    || null == mapStatus) {
                animateMapStatus(currentPoint, 20.0f);
            }
        } else if (null == mapStatus) {
            // 第一次定位时，聚焦底图
            setMapStatus(currentPoint, 20.0f);
        }

        if (showMarker) {
            addMarker(currentPoint);
        }
    }

    public Marker addOverlay(LatLng currentPoint, BitmapDescriptor icon, Bundle bundle) {
        if (baiduMap == null) {
            return null;
        }
        OverlayOptions overlayOptions = new MarkerOptions().position(currentPoint)
                .icon(icon).zIndex(9).draggable(true);
        Marker marker = (Marker) baiduMap.addOverlay(overlayOptions);
        if (null != bundle) {
            marker.setExtraInfo(bundle);
        }
        return marker;
    }

    /**
     * 添加地图覆盖物
     */
    public void addMarker(LatLng currentPoint) {
        if (null == mMoveMarker) {
            mMoveMarker = addOverlay(currentPoint, BitmapDescriptorFactory.fromResource(R.mipmap.icon_point), null);
            return;
        }

        if (null != lastPoint) {
            moveLooper(currentPoint);
        } else {
            lastPoint = currentPoint;
            mMoveMarker.setPosition(currentPoint);
        }
    }

    /**
     * 移动逻辑
     */
    public void moveLooper(LatLng endPoint) {
        mMoveMarker.setPosition(lastPoint);
        mMoveMarker.setRotate((float) CommonUtil.getAngle(lastPoint, endPoint));

        double slope = CommonUtil.getSlope(lastPoint, endPoint);
        // 是不是正向的标示（向上设为正向）
        boolean isReverse = (lastPoint.latitude > endPoint.latitude);
        double intercept = CommonUtil.getInterception(slope, lastPoint);
        double xMoveDistance = isReverse ? CommonUtil.getXMoveDistance(slope) : -1 * CommonUtil.getXMoveDistance(slope);

        for (double latitude = lastPoint.latitude; latitude > endPoint.latitude == isReverse; latitude =
                latitude - xMoveDistance) {
            LatLng latLng;
            if (slope != Double.MAX_VALUE) {
                latLng = new LatLng(latitude, (latitude - intercept) / slope);
            } else {
                latLng = new LatLng(latitude, lastPoint.longitude);
            }
            mMoveMarker.setPosition(latLng);
        }
    }

    /**
     * 绘制运动轨迹
     */
    public void drawPolyline(List<LatLng> points, List<Double> speeds) {
        if (points == null || points.size() < 2 || baiduMap == null) {
            return;
        }

        if (null != polylineOverlay) {
            polylineOverlay.remove();
            polylineOverlay = null;
        }
        List<Integer> colors = getColorsBySpeeds(speeds);
        // 添加路线（轨迹）
        OverlayOptions polylineOptions = new PolylineOptions().width(10).color(mContext.getColor(R.color.blue1))
                .dottedLineType(PolylineDottedLineType.DOTTED_LINE_CIRCLE).points(points).colorsValues(colors);
        polylineOverlay = baiduMap.addOverlay(polylineOptions);
    }

    public void drawPolylineDynamic(List<LatLng> points, List<Double> speeds) {
        if (points == null || points.size() < 2 || baiduMap == null) {
            return;
        }
        if (null != polylineOverlay) {
            polylineOverlay.remove();
            polylineOverlay = null;
        }
        int[] colors = getColorsBySpeeds1(speeds);
        // 添加路线（轨迹）
        TraceOptions traceOptions = new TraceOptions().animationTime(5000).animate(true)
                .colors(colors).useColorArray(true).width(10).points(points);
        // 添加轨迹动画
        baiduMap.addTraceOverlay(traceOptions, null);
    }

    /**
     * 绘制起点终点
     */
    public void drawStartAndEnd(LatLng start, LatLng end) {
        addOverlay(start, BitmapDescriptorFactory.fromResource(R.drawable.ic_start_point), null);
        addOverlay(end, BitmapDescriptorFactory.fromResource(R.drawable.ic_end_point), null);
    }

    private List<Integer> getColorsBySpeeds(List<Double> speeds) {
        // 添加路线（轨迹）
        List<Integer> colors = new ArrayList<>();
        ArgbEvaluator evaluator = new ArgbEvaluator();
        int startColor = Color.parseColor("#2860fe");
        int centerColor = Color.parseColor("#f38017");
        int endColor = Color.parseColor("#fd4840");
        double maxSpeed = 44.722;
        double mediumSpeed = 6;
        for (double speed : speeds) {
            int gradientColor;
            if (speed < mediumSpeed) {
                float rate = (float) (speed / mediumSpeed);
                gradientColor = (int) evaluator.evaluate(rate, startColor, centerColor);
            } else {
                float rate = (float) ((speed - mediumSpeed) / (maxSpeed - mediumSpeed));
                gradientColor = (int) evaluator.evaluate(rate, centerColor, endColor);
            }
            colors.add(gradientColor);
        }
        return colors;
    }

    private int[] getColorsBySpeeds1(List<Double> speeds) {
        // 添加路线（轨迹）
        int[] colors = new int[speeds.size()];
        ArgbEvaluator evaluator = new ArgbEvaluator();
        int startColor = Color.parseColor("#2860fe");
        int centerColor = Color.parseColor("#f38017");
        int endColor = Color.parseColor("#fd4840");
        double maxSpeed = 44.722;
        double mediumSpeed = 6;
        int i = 0;
        for (double speed : speeds) {
            int gradientColor;
            if (speed < mediumSpeed) {
                float rate = (float) (speed / mediumSpeed);
                gradientColor = (int) evaluator.evaluate(rate, startColor, centerColor);
            } else {
                float rate = (float) ((speed - mediumSpeed) / (maxSpeed - mediumSpeed));
                gradientColor = (int) evaluator.evaluate(rate, centerColor, endColor);
            }
            colors[i] = gradientColor;
            i++;
        }
        return colors;
    }

    public void drawPolyline(int color, List<LatLng> points) {
        if (points == null || points.size() <= 0) {
            return;
        }
        // 添加路线（轨迹）
        OverlayOptions polylineOptions = new PolylineOptions().width(10).color(mContext.getColor(R.color.blue1))
                .dottedLineType(PolylineDottedLineType.DOTTED_LINE_CIRCLE).points(points);
        if (baiduMap == null) {
            return;
        }
        polylineOverlay = baiduMap.addOverlay(polylineOptions);
    }

    public void animateMapStatus(LatLng point, float zoom) {
        MapStatus.Builder builder = new MapStatus.Builder();
        mapStatus = builder.target(point).zoom(zoom).build();
        baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(mapStatus));
    }

    public void setMapStatus(LatLng point, float zoom) {
        MapStatus.Builder builder = new MapStatus.Builder();
        mapStatus = builder.target(point).zoom(zoom).build();
        baiduMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(mapStatus));
    }

    public void refresh() {
        LatLng mapCenter = baiduMap.getMapStatus().target;
        float mapZoom = baiduMap.getMapStatus().zoom - 1.0f;
        setMapStatus(mapCenter, mapZoom);
    }

    public static double[] getFourCornerGps(List<LatLng> points) {
        if (points.size() == 0) {
            return null;
        }
        double longitudeLeft = points.get(0).longitude;
        double longitudeRight = points.get(0).longitude;
        double latitudeTop = points.get(0).latitude;
        double latitudeBottom = points.get(0).latitude;
        for (LatLng point : points) {
            if (point.longitude < longitudeLeft) {
                longitudeLeft = point.longitude;
            }
            if (point.longitude > longitudeRight) {
                longitudeRight = point.longitude;
            }
            if (point.latitude > latitudeTop) {
                latitudeTop = point.latitude;
            }
            if (point.latitude < latitudeBottom) {
                latitudeBottom = point.latitude;
            }
        }
        double[] gps = new double[4];
        gps[0] = longitudeLeft;
        gps[1] = longitudeRight;
        gps[2] = latitudeTop;
        gps[3] = latitudeBottom;
        return gps;
    }

    public static LatLng getMapCenter(double[] gps) {
        if (gps == null) {
            return null;
        }
        return new LatLng((gps[2] + gps[3]) / 2, (gps[0] + gps[1]) / 2);
    }

    public static float getMapZoom(double[] gps) {
        if (gps == null) {
            return 17;
        }
        double height = DistanceUtil.getDistance(new LatLng(gps[2], gps[0]), new LatLng(gps[3], gps[0]));
        double width = DistanceUtil.getDistance(new LatLng(gps[2], gps[0]), new LatLng(gps[2], gps[1]));
        if (height > width) {
            width = height;
        }
        return (float) (-Math.log(1.414 * width / 21400 / 8000) / Math.log(2));
    }
}